home *** CD-ROM | disk | FTP | other *** search
/ PCMania 64 / PCMania CD64_1.iso / phy / phy003 / files / articulo.t06 < prev    next >
Encoding:
Text File  |  1997-02-01  |  22.5 KB  |  394 lines

  1. ε                   Curso de programación en assembler (y III)π
  2.  
  3.                              εEl primer programaπ
  4.  
  5.   Hoy, por fin, abordaremos el primer ejemplo práctico en assembler. El primer
  6. programa que haremos será (como no) el δ"hola mundo"π. Pero antes de poder darle
  7. caña al ensamblador necesitamos tener alguno... la verdad es que todos teneis
  8. uno en vuestro PC, el ΩDebugπ, pero cuando hay que hacer cosas complicadas se
  9. hace imposible y por eso a lo largo del curso pasaremos un poco de él (excepto
  10. en este artículo) y nos centraremos en el ΩTurbo Assemblerπ y el ΩA86π que al ser
  11. shareware y tener una sintaxis simplificada os ayudará a empezar.
  12.   El Debug del DOS se invoca escribiendo δ'DEBUG'π en la linea de comandos y si
  13. quieres puedes poner detrás el nombre del programa a debuggear o a crear.
  14. Para hacer el δ"hola mundo"π entraremos escribiendo:
  15.  
  16.     ΓDEBUG hola.comπ
  17.  
  18. lo primero que el programa nos dirá es que hemos cometido un error porque el
  19. fichero 'δhola.comπ' no existe (si no nos da el error es que si existe y lo
  20. sobre-escribiremos). Ahora nos encontramos con un prompt que es una rallita '-'
  21. y ahí es donde deberemos entrar los comandos, por ejemplo 'δ?π' te mostrará
  22. todos los posibles. El que más nos va a interesar de momento es 'δaπ' que nos
  23. permite ensamblar directamente las intrucciones que entremos.
  24.   La primera instrucción que veremos hoy (y la que es más usada) será ΩMOVπ.
  25. Con ella conseguimos copiar el contenido de una variable, registro, constante
  26. en otro. Su prototipo es bastante sencillo:
  27.  
  28.         ΓMOV     <destino>, <origen>π
  29.  
  30. donde ∞<origen>π será el valor que copiaremos en ∞<destino>π. En general, en el
  31. ensamblador estandard de los 80X86 se especifica primero el destino y luego
  32. el origen como veremos en siguientes instrucciones. Un registro es una especie
  33. de variable que se guarda muy cerquita del procesador y por ello se accede a
  34. ella de forma muy rápida. Una variable la consideraremos una porción de memoria
  35. de tamaño δBYTEπ, δWORDπ... que podrá tomar distintos valores según lo que queramos
  36. hacer. Una constante será un valor que definiremos cuando creemos el código
  37. fuente y que no se podrá cambiar bajo ningún concepto.
  38.   Los registros son una parte fundamental de la arquitectura de un ordenador
  39. que ayudan al programador a acelerar los programas. Existen 4 registros llama-
  40. dos "de uso general" que son δAXπ, δBXπ, δCXπ y δDXπ de 16bits cada uno y divididos en
  41. dos partes de 8bits (parte alta-high y parte baja-low):
  42.  
  43.          Γ  AX --> AH - ALπ
  44.          Γ  BX --> BH - BLπ
  45.          Γ  CX --> CH - CLπ
  46.          Γ  DX --> DH - DLπ
  47.  
  48. Existen tambien otros registros no importantes de momento como son δCSπ, δSSπ, δSPπ,
  49. δDIπ... Simplemente mencionar el registro δDSπ que es un registro de segmento que
  50. lo que hace es apuntar al segmento de memoria sobre el que se opera (recordad
  51. lo que deciamos de la memoria segmentada del PC). Por ejemplo, si decimos que
  52. δDS:DXπ apunta a una cadena de texto, lo que queremos decir es que en el segmento
  53. δDSπ si nos desplazamos δDXπ posiciones nos encontraremos con una ristra de bytes
  54. que definen una cadena de texto; a δDSπ se le llamaria segmento y a δDXπ se le
  55. llamaria offset o desplazamiento.
  56.   Bueno veamos como queda el programa y seguimos explicando cosas a partir del
  57. mismo:
  58.  
  59. Γ        mov ax, cs              [1]π
  60. Γ        mov ds, ax              [2]π
  61. Γ        mov dx, 110             [3]π
  62. Γ        mov ah, 9               [4]π
  63. Γ        int 21                  [5]π
  64. Γ        mov ax, 4c00            [6]π
  65. Γ        int 21                  [7]π
  66. Γ        db 'Hola mundo!!$'      [8]π
  67.  
  68. para guardarlo debemos presionar δENTERπ, escribir 'ΩRCXπ', pulsar δENTERπ, escribir
  69. la longitud del programa a guardar y δENTERπ y escribir 'Ωwπ' (y δENTERπ :). Si te
  70. dice que hay algún error es que no has hecho algo bien. En este caso el tamaño
  71. del programa a almacenar es δ1Dπ (habrás observado que en el Debug todos los
  72. números se deben escribir en hexadecimal.
  73.   Vamos con el comentario línea por línea del programa (supongo que te darás
  74. cuenta de que no debes escribir los numeros entre corchetes ;). En la primera
  75. linea vemos una de las asignaciones δMOVπ de las que hablabamos antes, el regis-
  76. tro δCSπ (que apunta al trozo de código) se cópia en δAXπ. La segunda instrucción
  77. hace algo parecido, pero esta vez cópia en un registro de segmento lo que habia
  78. en δAXπ (que mira tu por donde es lo mismo que lo que hay en δCSπ). En la linea 3
  79. se asigna una constante a un registro, δDXπ pasará a valer φ110hπ. Lo mismo que
  80. antes se hace en la cuarta línea solo que ahora se trata de un registro de
  81. 8bits (la mitad de arriba de δAXπ). Las instrucciones 5 y 7 son llamadas a
  82. interrupciones y las veremos ahora enseguida. La instrucción 6 es otra vez una
  83. asignación de una constante a un registro (observa lo frecuentes que son las
  84. instrucciones δMOVπ). Y por último, la palabra clave 'δdbπ' no se trata de una
  85. instrucción própiamente dicha, sino que sirve para definir una espécie de
  86. matriz o array de δBYTESπ (como en los lenguajes de alto nivel).
  87.   Todo esto está muy bien, ¿pero donde está el análisis semántico? Pues aquí
  88. mismo... Si miramos lo que hace el programa en las 2 primeras líneas es meter
  89. en 'δdsπ' el contenido de 'δcsπ', entonces ¿por que no hacer 'δMOV DS,CSπ' directa-
  90. mente? Sencillo, porque no se puede: los registros de segmento no pueden
  91. asignarse a otros registros de segmento, por tanto, cada vez que queramos
  92. hacer algo así, tendremos que copiar a un registro auxiliar el contenido del
  93. origen. Las dos siguientes líneas (3 y 4) son una simple preparación para la
  94. interrupción que se lanzará en la línea 5 (tambien forman parte de esa
  95. "δpreparaciónπ" las instrucciones 1 y 2). Las interrupciones las veremos más
  96. a fondo ahora mismo, pero baste decir que la interrupción que llamamos primero
  97. nos permite ver una cadena en pantalla y la segunda hace que regresemos al
  98. sistema operativo.
  99.  
  100.                              ε Las interrupcionesπ
  101.  
  102.   Las interrupciones son un método de simplificar la tarea al programador ya
  103. son como pequeñas funciones o procedimientos que devuelven valores valiosos o
  104. simplemente hacen algo que resultaria difícil de programar manualmente. Los
  105. "parámetros" se le pasan en los registros y los valores nos los devuelve en
  106. registros tambien. En el PC hay exactamente δ256π servicios de interrupción
  107. (del 00h al FFh) que se dividen en centenares de subservicios por lo que para
  108. programar en assembler se hace necesaria una lista suficientemente completa de
  109. todas las interrupciones como la de ΩRalf Brownπ (que podeis encontrar en muchos
  110. CD-ROMs de share).
  111.   Si comprendemos apróximadamente este funcionamiento ya estamos en disposición
  112. de ver que es exactamente lo que se hacia en el programa de ejemplo. La δINT 21hπ
  113. es la interrupción que lleva el grueso de los servicios del sistema operativo
  114. (DOS), tiene unos 200 subservicios y debe identificar a cual de ellos se va
  115. a llamar en cada momento. Para ello, en el registro δAHπ debemos guardar el
  116. número de subservicio (en nuestro caso el 09) y llamar a los servicios con
  117. los parámetros correspondientes. La lista de Ralf Brown para este caso indica
  118. lo siguiente:
  119.  
  120. Θ--------D-2109-------------------------------π
  121. ΘINT 21 - DOS 1+ - WRITE STRING TO STANDARD OUTPUTπ
  122. Θ        AH = 09hπ
  123. Θ        DS:DX -> '$'-terminated stringπ
  124. ΘReturn: AL = 24h (the '$' terminating the string, despite official docs whichπ
  125. Θ                state that nothing is returned) (at least DOS 3.3-5.0)π
  126. ΘNotes:  ^C/^Break are checked, and INT 23 is called if either pressedπ
  127. Θ        standard output is always the screen under DOS 1.x, but may beπ
  128. Θ          redirected under DOS 2+π
  129. Θ        under the FlashTek X-32 DOS extender, the pointer is in DS:EDXπ
  130. ΘSeeAlso: AH=02h,AH=06h"OUTPUT"π
  131.  
  132.   Lo primero que se indica es el número, servicio y nombre de la interrupción
  133. para poder localizarla. Luego están los parámetros de entrada que en nuestro
  134. caso son δAH=09hπ (lógicamente!!) y δDS:DXπ=<Cadena terminada con '$'>. Observa el
  135. código fuente del programa y verás como comienzas a ligar cabos sueltos. Según
  136. esto, en δALπ devolverá el valor φ24hπ que corresponde al valor ASCII de 'δ$π' (hace
  137. tambien una observación de que esto no está documentado). Como observaciones
  138. nos dice que pulsando CTRL-C o CTRL-PAUSA haremos saltar la interrupción 23h
  139. (esto lo veremos en un ejemplo de otro número) que hace que se interrumpa el
  140. programa. Tambien nos dice que es conveniente ver los subservicios 02h y 06h.
  141.   Veamos nuestro programa como asigna a δDS:DXπ la cadena terminada en $ que
  142. aparece al final del código: primero, como ya habiamos visto, cópia el segmento
  143. de código en DS y luego entra el valor constante φ110hπ en δDXπ. Si en el Debug
  144. escribimos:
  145.  
  146. Γ     u 100π
  147.  
  148. veremos lo que hemos introducido y podremos observar que al principio de cada
  149. línea aparece una cosa así:
  150.  
  151. Γ   XXXX:YYYYπ
  152.  
  153. eso no es ni más ni menos que la dirección segmentada donde estamos guardando
  154. el código del programa; XXXX es el segmento e YYYY es el desplazamiento u
  155. offset dentro de ese segmento. Por tanto, la dirección que yo he de pasar es
  156. el segmento donde reside la cadena (que resulta ser el del código) y el offset
  157. dentro de ese segmento que es φ110hπ y que si miras el programa desensamblado
  158. (despues de usar el comando 'δuπ' del debug) es φ0110π precisamente.
  159.   Un posible pero a todo esto es: pero, ¿porque has entrado el offset como
  160. constante y el segmento lo has sacado del registro CS? La respuesta a esto
  161. la entenderás mejor cuando veamos los programas COM y EXE, aunque es sencilla
  162. (a priori); cuando el sistema operativo carga un programa (COM en este caso)
  163. lo que hace es buscar un segmento de memoria libre (los TSR ocupan memoria y
  164. el própio SO) y lo carga a partir de la dirección φ0100hπ, por tanto podemos
  165. saber el offset pero no el segmento donde se cargará.
  166.  
  167.                                    εEl Debugπ
  168.  
  169.   A parte de ensamblar y desensamblar programas, el debug (y esa es su razón
  170. de ser) se usa para ejecutar programas paso por paso como se hace en los
  171. IDEs de los lenguajes de alto nivel. Para ejecutar un paso (step) de un trozo
  172. de código usaremos 'p' y para trazar usaremos 'δtπ'. La diferencia entre una
  173. instrucción y otra es simplemente que con 'δtπ' si encontramos una INT (o algunas
  174. instrucciones que veremos para hacer llamadas a subprocedimientos) entraremos
  175. dentro de ella, mientras que con 'p' ejecutaremos el código linealmente. Para
  176. lo que sabemos ahora es suficiente con 'δpπ' ∞(no usar 't' delante de INT!!)π.
  177.   La utilidad de todo esto cuando se está comenzando es increible, así podrás
  178. ver como las instrucciones e interrupciones modifican los registros. Hablando
  179. de registros, el registro IP es un registro que apunta a la instrucción que
  180. está siendo ejecutada en cada momento dentro del segmento δCSπ del que ya sabia-
  181. mos algo. Vamos a ver un ejemplo de trazeado de un programa (el "hola mundo")
  182. y observaremos como cambian los registros:
  183.  
  184. ΓAX=109FBX=0000CX=001DDX=0000SP=FFFEBP=0000SI=0000DI=0000π
  185. ΓDS=109FES=109FSS=109FCS=109FIP=0102 NV UP EI PL NZ NA PO NC π
  186. Γ109F:0102 8ED8          MOV     DS,AXπ
  187.  
  188. Al ejecutarse la primera instrucción AX ha adquirido el valor de CS. Podemos
  189. observar tambien que DS es igual a CS y que no es necesario copiarlo, pero
  190. siempre es mejor asegurarse de hacer las cosas bien. La instrucción 'p' nos
  191. muestra tambien cual será la siguiente instrucción a ejecutar (MOV DS,AX).
  192. Observa el valor de CS:IP y la dirección de la siguiente instrucción a ser
  193. ejecutada y fíjate que es el mismo.
  194.  
  195. ΓAX=109FBX=0000CX=001DDX=0000SP=FFFEBP=0000SI=0000DI=0000π
  196. ΓDS=109FES=109FSS=109FCS=109FIP=0104 NV UP EI PL NZ NA PO NCπ
  197. Γ109F:0104 BA1001        MOV     DX,0110π
  198.  
  199. Trás esta instrucción no podemos observar nada nuevo en DS ya que el valor era
  200. el mismo que tenia anteriormente. Lo que si podemos ver es que CS:IP sigue
  201. apuntando a la siguiente instrucción a ejecutar y esto será así siempre.
  202.  
  203. ΓAX=109FBX=0000CX=001DDX=0110SP=FFFEBP=0000SI=0000DI=0000π
  204. ΓDS=109FES=109FSS=109FCS=109FIP=0107 NV UP EI PL NZ NA PO NC π
  205. Γ109F:0107 B409          MOV     AH,09π
  206.  
  207. Podemos ver como ha cambiado DX, pasando del valor 0000h al 0110h que es el
  208. offset de la cadena.
  209.  
  210. ΓAX=099FBX=0000CX=001DDX=0110SP=FFFEBP=0000SI=0000DI=0000π
  211. ΓDS=109FES=109FSS=109FCS=109FIP=0109 NV UP EI PL NZ NA PO NC π
  212. Γ109F:0109 CD21          INT     21π
  213.  
  214. Observa la parte alta de AX que ha pasado a valer 09h. Por si todavia no tenias
  215. claro eso de la parte alta y la baja mira el valor que tenia AX antes (AX=109F)
  216. y mira el que tiene ahora (δAX=099Fπ) lo que ha cambiado es la parte de mayor
  217. peso del registro. Si hubiesemos actuado sobre AL en lugar de AH, el 9Fh de AX
  218. hubiese pasado a 09h.
  219.  
  220. ΓHola mundo!!π
  221. ΓAX=0924BX=0000CX=001DDX=0110SP=FFFEBP=0000SI=0000DI=0000     π
  222. ΓDS=109FES=109FSS=109FCS=109FIP=010B NV UP EI PL NZ NA PO NC π
  223. Γ109F:010B B8004C        MOV     AX,4C00π
  224.  
  225. En este paso se ejecuta la interrupción y por tanto se muestra el mensaje en
  226. pantalla. Como se decia en la lista de Ralf Brown, AL tiene ahora el valor
  227. 24h y los demás registros permanecen inalterados (a excepción de IP, claro!!).
  228.  
  229. ΓAX=4C00BX=0000CX=001DDX=0110SP=FFFEBP=0000SI=0000DI=0000π
  230. ΓDS=109FES=109FSS=109FCS=109FIP=010E NV UP EI PL NZ NA PO NC π
  231. Γ109F:010E CD21          INT     21π
  232.  
  233. Vemos como AX ha adquirido el valor 4C00h para llamar a la interrupción 21h.
  234. Este subservicio es el que nos permite regresar al prompt del DOS pasandole
  235. en AH el valor 4Ch (que indica el número de subservicio) y en AL el llamado
  236. "δerrorlevelπ" que devuelve el programa (en este caso 00h). Si volvemos a te-
  237. clear el comando 'p' saldremos al DOS ya que se ejecutará la interrución (como
  238. podemos ver en el campo "siguiente instrucción").
  239.   Tal vez, si escribes 'Ωu 100π' para ver el programa que has hecho, te sorprenda
  240. ver que la cadena 'hola mundo!!$' no aparece por ningún sítio. Ello es porque
  241. cuando le dices al debug que desensamble un trozo de código, interpreta que
  242. ese trozo es de intrucciones y por ello trata de dar un significado a la ristra
  243. de bytes que componen la cadena. Para ver las cadenas que definamos en nuestro
  244. programa, deberemos escribir la instrucción 'd 100' que significa "dump"
  245. (volcar) y que hace un caracteristico listado hexadecimal.
  246.   Si todavia no te has dado cuenta de que significado tiene ese 100 que ponemos
  247. detrás de las instrucciones 'd' y 'u', deberias de haberte dado cuenta de que
  248. se trata de la dirección (sólo offset, se supone que el segmento es CS) donde
  249. el debug debe empezar a volcar o desensamblar. Opcionalmente tambien puedes
  250. poner detrás otro offset para decirle cuando debe acabar, aunque si no lo
  251. haces no pasa nada ya que entiende que quieres un trozito.
  252.   La instrucción 'w' (write) sirve para almacenar en disco el programa (re-
  253. cuerda que ya la has usado para salvar el programa) desde la posición CS:0100h
  254. hasta el offset dentro de CS almacenado en CX más 100h. En realidad en CX lo
  255. que debes guardar es la longitud del programa (en el "hola mundo" era 1Dh
  256. porque despues de introducir la última instrucción [la del mensaje] apareció
  257. como siguiente dirección para ensamblar la δXXXX:01D1hπ; vuelve a reescribir el
  258. programa para observarlo). Para poner un valor en un registro, debemos usar
  259. la instrucción 'r' que usado sin parámetros devuelve el valor de los registros
  260. y con un registro como parámetro permite su modificación ('rcx' en este caso).
  261.   Otra instrucción interesante es 'δgπ' (go) que permitirá que un programa que
  262. estamos trazando con 't' o 'p' pueda ser ejecutado hasta su finalización. Si
  263. entramos al programa sin especificar un nombre para el archivo que queremos
  264. almacenar en disco o queremos poner otro usaremos la intrucción 'n' pasandole
  265. como parámetro el nombre del fichero de salida con extensión COM (no se pueden
  266. hacer EXEs con el debug).
  267.  
  268.                           εInstrucciones aritméticasπ
  269.  
  270.   Las instrucciones aritméticas son las que permiten operar con los registros
  271. y hacer sencillos cálculo en complemento a dos (ver anteriores artículos).
  272. Podemos sumar, restar, multiplicar y dividir directamente y podemos realizar
  273. operaciones más complicadas a base de estas más simples. Los prototipos de las
  274. instrucciones son estos:
  275.  
  276. Γ            ADD  <destino>, <origen>π
  277. Γ            SUB  <destino>, <origen>π
  278. Γ            MUL  <multipl>π
  279. Γ            IMUL <multipl>π
  280. Γ            DIV  <divisor>π
  281. Γ            IDIV <divisor>π
  282.  
  283.   Lo primero que se observa es que hay 2 instrucciones para multiplicar y 2
  284. más para dividir. Las instrucciones δMULπ y δDIVπ consideran números sin signo,
  285. mientras δIMULπ e δIDIVπ los consideran con signo. Para sumar 2 registros lo que
  286. hacemos es poner el destino delante y lo que le sumaremos detrás. Es equiva-
  287. lente a la instrucción de C "+=". Veamos un par de ejemplos:
  288.  
  289. Γ        MOV     AX, 25π         φ ;  AX pasa a valer 25π
  290. Γ        MOV     BX, 35π         φ ;  BX pasa a valer 35π
  291. Γ        ADD     AX, BXπ         φ ;  BX se mantiene y AX valdrá 25+35=60π
  292. Γπ
  293. Γ        MOV     AX, 100π        φ ;  AX = 100π
  294. Γ        MOV     BX, 50 π        φ ;  BX = 50π
  295. Γ        ·····          π        φ ;  Queremos que AX y BX no cambien, usamosπ
  296. Γ        MOV     CX, AX π        φ ; otro registro para almacenar el resultado.π
  297. Γ        ADD     CX, BX π        φ ;  CX = 150, AX = 100, BX = 50π
  298.  
  299.   Tambien podemos operar con memoria, pero recordando siempre que el 80x86
  300. no nos permite operaciones de memoria a memoria (es incorrecto MOV [v1], [v2]).
  301. Para la resta lo mismo, se restará el "origen" al "destino", es decir, como
  302. si hiciesemos en un HLL "destino=destino-origen". Algunos ejemplos:
  303.  
  304. Γ        MOV     AX, 100         φ;  AX vale 100π
  305. Γ        SUB     AX, 10          φ;  AX valdrá 90π
  306. Γ        MOV     BX, 90          φ;  BX = 90π
  307. Γ        SUB     AX, BX          φ;  AX se hace 0π
  308.  
  309. Γ        MOV     AX, 25          φ;  AX = 25π
  310. Γ        MOV     BX, 15          φ;  BX = 15π
  311. Γ        ·····                   φ;  Supongamos que queremos guardar en memoriaπ
  312. Γ        MOV     DS:[130h], AX   φ; AX - BXπ
  313. Γ        SUB     DS:[130h], BX   φ;  En memoria 10π
  314.  
  315.   Despues de ver este último ejemplo tengo que aclarar un par de cosas. Lo
  316. primero, cuando no escriba una "h" o una "o" al final del número, estaré
  317. escribiendo los números en decimal (a no ser que el código este diseñado
  318. explícitamente para ser usado en el debug). Lo segundo, que cuando queramos
  319. almacenar en memoria un valor, deberemos haber definido una zona para el
  320. almacenamiento de memoria (con las instrucciones δDBπ, δDWπ o δDDπ que hemos visto
  321. superficialmente) y luego recordar la dirección donde están definidas para
  322. acceder a ellas escribiendo su dirección entre corchetes. Este sistema tan
  323. arcaico es sólo necesario con el debug, ya que todos los ensambladores
  324. modernos incorporan etiquetas (en el próximo número). Por ejemplo, tomemos
  325. del debug un trozo de código que haga uso de esta caracteristica:
  326.  
  327. Γ10BB:0100 8CC8          MOV     AX,CS         φ  ;  Primero metemos el segmentoπ
  328. Γ10BB:0102 8ED8          MOV     DS,AX         φ  ; correcto.                   π
  329. Γ10BB:0104 B85000        MOV     AX,0050π                                       π
  330. Γ10BB:0107 BB3000        MOV     BX,0030 φ        ;  Los datos a restar.        π
  331. Γ10BB:010A A31601        MOV     [0116],AXφ       ;  Escribimos a memoria.      π
  332. Γ10BB:010D 291E1601      SUB     [0116],BXφ       ;  Restamos de memoria.       π
  333. Γ10BB:0111 B8004C        MOV     AX,4C00   φ      ;  Función de salir al DOS    π
  334. Γ10BB:0114 CD21          INT     21     φ         ;  Hasta luego lucas!         π
  335. Γ10BB:0116 0000          DW      0      φ ;  Aquí es donde definimos la WORD queπ
  336.                                        φ ; almacenará los numeritos.            π
  337.  
  338.   Las instrucciones multiplicativas tienen un aspecto más complicado, sólo
  339. tienen 1 parámetro. Para hacer una multiplicación se coge el acumulador y se
  340. opera con el registro o posición de memoria que le pasemos como parámetro.
  341. Pero, ¿que es eso del acumulador? Pues depende, puede ser δALπ o δAXπ. Como sabrás
  342. (si prestaste atención en los anteriores números) cuando multiplicamos dos
  343. números de n-bits, la mayor de las cifrás que tendremos será de 2n-bits. Así,
  344. pues, se estandariza la operación de multiplicación y si se quiere multiplicar
  345. 2 números deberán tener los mismos bits (8 o 16) y el resultado se almacenará
  346. en un registro de 2n-bits. En definitiva, si queremos multiplicar un número de
  347. 8-bits el acumulador será δALπ y si es de 16 será δAXπ. Para almacenar el resultado
  348. de los de 8-bits usaremos AX y para los de 16 usaremos el par δDX-AXπ donde DX
  349. serán los 16-bits de mayor peso y AX los 16 de menor. Ejemplos:
  350.  
  351. Γ        MOV     AX, 10       φ   ;  AX = 10π
  352. Γ        MOV     BX, 50       φ   ;  BX = 50 π
  353. Γ        MUL     BX           φ   ;  DX-AX = AX * BX,  y como 500 cabe en 16 bits π
  354.                               φ  ; AX valdrá 500 y DX será 0.                     π
  355.  
  356. Γ        MOV     AL, 120      φ   ;  AL = 120π
  357. Γ        MOV     CL, 40       φ   ;  CL = 40 π
  358. Γ        MUL     CL           φ   ;  AX = AL * CL = 120 * 40 = 4800π
  359.  
  360.   La división es lo contrario de la multiplicación, cuando uso el divisor de
  361. 8-bits, el acumulador es de 16 y cuando lo uso de 16-bits, el acumulador será
  362. el de 32 (DX-AX). Vamos directamente con un ejemplo:
  363.  
  364. Γ        MOV     CL, 100     φ    ;  CL = 100π
  365. Γ        MOV     BL, 10      φ    ;  BL = 10. Queremos dividir CL/BL:π
  366. Γ        MOV     AL, CL      φ    ;  Tenemos un problema, AH puede contener unπ
  367. Γ        MOV     AH, 0       φ    ; valor distinto de 0; pues lo "borramos".π
  368. Γ        DIV     BL          φ    ;  AL = 100 / 10 = 10                    π
  369.  
  370.   El cociente de esta operación de división se almacena en AL y el resto lo
  371. hace en δAHπ. Como el acumulador para divisores de 8-bits es de 16, hemos copiado
  372. a δAXπ el dividendo, haciendo 0 la parte de arriba (más adelante veremos como
  373. hacer esto en una sóla instrucción). Si usasemos un registro de 16-bits
  374. tendriamos que hacer δDX=0π.
  375.  
  376.   Creo que ya ha habido bastante por hoy, ¿no? En el próximo número veremos
  377. las instrucciones lógicas, los saltos, comparaciones y si hay tiempo las
  378. entradas y salidas, además de un especial interrupciones. Os dejo unos deberes
  379. para casa: determinad que valores contendrán los registros de uso general
  380. (δAXπ, δBXπ, δCXπ y δDXπ) al terminar el programa o decid si no es posible ensamblarlos
  381. por contener algún error (se deben hacer sin usar el PC):
  382.  
  383. Γ MOV     AX, 100         MOV     AX, 30          MOV     AL, 500π
  384. Γ MOV     BX, 200         MOV     BX, 10          MOV     BL, 100 π
  385. Γ ADD     AX, BX          MUL     BX              SUB     AL, BL   π
  386. Γ MUL     BX              DIV     BX              MUL     10π
  387. Γ                         ADD     AL, BXπ
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.